﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//Xna
using Microsoft.Xna.Framework;

namespace Puzzle_3D
{
    class Puzzle_TouchlessGestures
    {
        private static int SIZE = 250;
        private static int TIMESPAN = 1800;
        private static int GESTUREFOUNDTIME = 1200;
        private static int AVERAGECOUNT = 10;

        private Puzzle_RawPoint[] pointArray;
        private int index;
        private int firstPoint;
        private int lastPointAdded;
        private int foundTime;

        private Vector2 averageFirst;
        private Vector2 averageLast;

        private Puzzle root;
        private Puzzle_Menu menu;

        public Puzzle_TouchlessGestures(Puzzle_Menu _menu, Puzzle _root)
        {
            this.pointArray = new Puzzle_RawPoint[SIZE];
            this.lastPointAdded = 0;
            this.index = 0;
            this.foundTime = 0;

            this.menu = _menu;
            this.root = _root;

            this.averageFirst = new Vector2(0, 0);
            this.averageLast = new Vector2(0, 0);
        }

        public void addElement(Puzzle_RawPoint _point)
        {
            if (this.index != SIZE)
            {
                this.pointArray[this.index] = _point;
                this.lastPointAdded = this.index;
                this.index++;
            }
            else
            {
                for (int i = 1; i <= SIZE - 1; i++)
                {
                    this.pointArray[i - 1] = this.pointArray[i];
                }
                this.pointArray[SIZE - 1] = _point;
                this.lastPointAdded = SIZE - 1;
            }
        }

        private bool checkForTimespan()
        {
            bool found = false;
            for (int i = SIZE - 2; i >= 0 && !found; i--)
            {
                if (this.pointArray[i] != null && this.pointArray[this.lastPointAdded].timestampValue - this.pointArray[i].timestampValue >= TIMESPAN)
                {
                    this.firstPoint = i;
                    found = true;
                }
            }
            return found;
        }

        public void checkForGestures(GameTime _time)
        {
            if (this.checkForTimespan() && ((int)_time.TotalGameTime.TotalMilliseconds - this.foundTime >= GESTUREFOUNDTIME))
            {
                this.checkForButtonGesture();
                if (this.menu.isOptionMenu)
                {                
                    this.checkForSelectionGesture();
                    this.checkForScrollGesture();
                }
                if (this.menu.isFilterMenu)
                {
                    this.checkForFilterSelectionGesture();
                }
            }
        }

        private void checkForButtonGesture()
        {
            this.getAverageValues();
            int distance = (int)this.averageFirst.X - (int)this.averageLast.X;
            Vector2 startPoint = this.averageFirst;
            Vector2 endPoint = this.averageLast;
            if (distance >= 380)
            {
                Puzzle_MenuEntry[] entries;
                if (this.menu.isInfoMenu || this.menu.isOptionMenu || this.menu.isFilterMenu)
                {
                    entries = this.menu.backEntry;
                }
                else
                {
                    entries = this.menu.menuEntries;
                }
                foreach (Puzzle_MenuEntry entry in entries)
                {
                    int entryPositionY = (int)entry.getPosition().Y;
                    Microsoft.Xna.Framework.Rectangle entryRect = entry.getEntryRectangle(false);
                    Microsoft.Xna.Framework.Rectangle markerRect = new Microsoft.Xna.Framework.Rectangle((int)endPoint.X,
                       (int)endPoint.Y,
                       (int)(startPoint.X - endPoint.X),
                       20);
                    if ((startPoint.Y >= (entryPositionY - 10)) && (startPoint.Y <= (entryPositionY + 60)) &&
                        (endPoint.Y >= (entryPositionY - 10)) && (endPoint.Y <= (entryPositionY + 60)))
                    {
                        if (entryRect.Intersects(markerRect))
                        {
                            switch (entry.getName())
                            {
                                //Hauptmenu
                                case ("Start"):
                                    this.root.setIsGaming(true);
                                    break;
                                case ("Auswahl"):
                                    this.menu.isOptionMenu = true;
                                    break;
                                case ("Filter"):
                                    this.menu.isFilterMenu = true;
                                    break;
                                case ("Info"):
                                    this.menu.isInfoMenu = true;
                                    break;
                                case ("Exit"):
                                    if (!this.menu.isOptionMenu && !this.menu.isFilterMenu && !this.menu.isInfoMenu)
                                    {
                                        this.root.Exit();
                                    }
                                    break;                                
                                //zurueck Button
                                case ("Back"):
                                    if (this.menu.isOptionMenu)
                                    {
                                        this.menu.isOptionMenu = false;
                                    }
                                    else if (this.menu.isFilterMenu)
                                    {
                                        this.menu.isFilterMenu = false;
                                    }
                                    else if (this.menu.isInfoMenu)
                                    {
                                        this.menu.isInfoMenu = false;
                                    }
                                    break;
                            }
                            this.foundTime = this.pointArray[this.lastPointAdded].timestampValue;
                        }
                    }
                }
            }
        }

        private void checkForFilterSelectionGesture()
        {
            Microsoft.Xna.Framework.Rectangle[] filterRectLeft = new Microsoft.Xna.Framework.Rectangle[this.menu.filterEntries.Count()];
            Microsoft.Xna.Framework.Rectangle[] filterRectRight = new Microsoft.Xna.Framework.Rectangle[this.menu.filterEntries.Count()];
            Microsoft.Xna.Framework.Rectangle[] filterRectBottom = new Microsoft.Xna.Framework.Rectangle[this.menu.filterEntries.Count()];
            int count = 0;
            foreach (Puzzle_MenuEntry entry in this.menu.filterEntries)
            {
                filterRectLeft[count] = new Microsoft.Xna.Framework.Rectangle((int)(entry.getPosition().X - 10), (int)(entry.getPosition().Y - 15), 30, 30);
                filterRectRight[count] = new Microsoft.Xna.Framework.Rectangle((int)(entry.getPosition().X + 190), (int)(entry.getPosition().Y - 15), 30, 30);
                filterRectBottom[count] = new Microsoft.Xna.Framework.Rectangle((int)(entry.getPosition().X + 105), (int)(entry.getPosition().Y + 135), 100, 40);
                count++;
            }

            //Durchschnittswerte ermitteln
            this.getAverageValues();

            //Rectangles links oben und rechts oben
            Microsoft.Xna.Framework.Rectangle firstPointRect = new Microsoft.Xna.Framework.Rectangle((int)averageFirst.X,
                        (int)averageFirst.Y,
                        50,
                        50);
            Microsoft.Xna.Framework.Rectangle LastPointRect = new Microsoft.Xna.Framework.Rectangle((int)averageLast.X,
                        (int)averageLast.Y,
                        50,
                        50);
            //maximalen Y-Wert ermitteln
            int maxY = 0;
            int maxX = 0;
            for (int i = this.lastPointAdded; i >= 0 || i == this.firstPoint; i--)
            {
                if (this.pointArray[i].Ypos > maxY)
                {
                    maxY = this.pointArray[i].Ypos;
                    maxX = this.pointArray[i].Xpos;
                }

            }

            Microsoft.Xna.Framework.Rectangle maxRect = new Microsoft.Xna.Framework.Rectangle(maxX, maxY, 40, 40);
            count = 0;
            foreach (Puzzle_MenuEntry entry in this.menu.filterEntries)
            {
                if (filterRectLeft[count].Intersects(firstPointRect) && filterRectRight[count].Intersects(LastPointRect) && filterRectBottom[count].Intersects(maxRect))
                {
                    switch (entry.getName())
                    {
                        //Filtermenu
                        case ("Filter1"):
                            if (this.menu.filterOption != 1)
                            {
                                this.menu.filterOption = 1;
                                this.menu.filterEntries.ElementAt<Puzzle_MenuEntry>(1).activeEntry = false;
                                this.menu.filterEntries.ElementAt<Puzzle_MenuEntry>(2).activeEntry = false;
                            }
                            else
                            {
                                this.menu.filterOption = 0;
                            }
                            break;
                        case ("Filter2"):
                            if (this.menu.filterOption != 2)
                            {
                                this.menu.filterOption = 2;
                                this.menu.filterEntries.ElementAt<Puzzle_MenuEntry>(0).activeEntry = false;
                                this.menu.filterEntries.ElementAt<Puzzle_MenuEntry>(2).activeEntry = false;
                            }
                            else
                            {
                                this.menu.filterOption = 0;
                            }
                            break;
                        case ("Filter3"):
                            if (this.menu.filterOption != 3)
                            {
                                this.menu.filterOption = 3;
                                this.menu.filterEntries.ElementAt<Puzzle_MenuEntry>(0).activeEntry = false;
                                this.menu.filterEntries.ElementAt<Puzzle_MenuEntry>(1).activeEntry = false;
                            }
                            else
                            {
                                this.menu.filterOption = 0;
                            }
                            break;
                    }
                    this.foundTime = this.pointArray[this.lastPointAdded].timestampValue;
                    entry.activeEntry = !entry.activeEntry;
                }
                count++;
            }
        }

        private void checkForSelectionGesture()
        {
            Microsoft.Xna.Framework.Rectangle[] pictureRectLeft = new Microsoft.Xna.Framework.Rectangle[this.menu.imageList.Count];
            Microsoft.Xna.Framework.Rectangle[] pictureRectRight = new Microsoft.Xna.Framework.Rectangle[this.menu.imageList.Count];
            Microsoft.Xna.Framework.Rectangle[] pictureRectBottom = new Microsoft.Xna.Framework.Rectangle[this.menu.imageList.Count];
            int count = 0;
            foreach (Puzzle_Image image in this.menu.imageList)
            {
                pictureRectLeft[count] = new Microsoft.Xna.Framework.Rectangle((int)(image.ImagePosition.X - 10), (int)(image.ImagePosition.Y - 15), 20, 30);
                pictureRectRight[count] = new Microsoft.Xna.Framework.Rectangle((int)(image.ImagePosition.X + 140), (int)(image.ImagePosition.Y - 15), 20, 30);
                pictureRectBottom[count] = new Microsoft.Xna.Framework.Rectangle((int)(image.ImagePosition.X + 40), (int)(image.ImagePosition.Y + 85), 70, 40);
                count++;
            }
            
            //Durchschnittswerte ermitteln
            this.getAverageValues();

            //Rectangles links oben und rechts oben
            Microsoft.Xna.Framework.Rectangle firstPointRect = new Microsoft.Xna.Framework.Rectangle((int)averageFirst.X,
                        (int)averageFirst.Y,
                        40,
                        40);
            Microsoft.Xna.Framework.Rectangle LastPointRect = new Microsoft.Xna.Framework.Rectangle((int)averageLast.X,
                        (int)averageLast.Y,
                        40,
                        40);
            //maximalen Y-Wert ermitteln
            int maxY = 0;
            int maxX = 0;
            for(int i = this.lastPointAdded; i >= 0 || i == this.firstPoint; i--)
            {
                if (this.pointArray[i].Ypos > maxY)
                {
                    maxY = this.pointArray[i].Ypos;
                    maxX = this.pointArray[i].Xpos;
                }

            }

            Microsoft.Xna.Framework.Rectangle maxRect = new Microsoft.Xna.Framework.Rectangle(maxX, maxY, 40, 40);
            count = 0;
            foreach (Puzzle_Image image in this.menu.imageList)
            {
                if (pictureRectLeft[count].Intersects(firstPointRect) && pictureRectRight[count].Intersects(LastPointRect) && pictureRectBottom[count].Intersects(maxRect))
                {
                    if (image.isImageHighlighted && image.getScreenNumber() == this.menu.showImageScreenNumber)
                    {
                        image.isImageHighlighted = false;
                        this.menu.highlightCount--;
                        //bild aus Liste der Puzzle entfernen
                        this.menu.gameImages.Remove(image);
                    }
                    else if (image.getScreenNumber() == this.menu.showImageScreenNumber)
                    {
                        if (this.menu.highlightCount < this.menu.MAXHIGHLIGHTS)
                        {
                            image.isImageHighlighted = true;
                            this.menu.highlightCount++;
                            //Bild der Liste der Puzzle hinzufuegen
                            this.menu.gameImages.Add(image);
                        }
                    }
                    this.foundTime = this.pointArray[this.lastPointAdded].timestampValue;
                }
                count++;
            }
        }

        private void checkForScrollGesture()
        {
            int distanceUp = this.pointArray[this.firstPoint].Ypos - this.pointArray[this.lastPointAdded].Ypos;
            int distanceDown = this.pointArray[this.lastPointAdded].Ypos - this.pointArray[this.firstPoint].Ypos;
            int middlePoint = this.pointArray[this.firstPoint + ((this.lastPointAdded - this.firstPoint)/2)].Xpos;

            if ((distanceUp >= 400 || distanceDown >= 400) &&
                (this.pointArray[this.firstPoint].Xpos >= 650 && this.pointArray[this.lastPointAdded].Xpos >= 650 && middlePoint >= 650))
            {
                if (this.pointArray[this.firstPoint].Ypos > this.pointArray[this.lastPointAdded].Ypos)
                {
                    //aufwaerts scrollen
                    if (this.menu.showImageScreenNumber < this.menu.imageScreens)
                    {
                        this.menu.showImageScreenNumber++;
                    }
                    else
                    {
                        this.menu.showImageScreenNumber = 1;
                    }
                }
                else
                {
                    //abwaerts scrollen
                    if (this.menu.showImageScreenNumber == 1)
                    {
                        this.menu.showImageScreenNumber = this.menu.imageScreens;
                    }
                    else
                    {
                        this.menu.showImageScreenNumber--;
                    }
                }
                this.foundTime = this.pointArray[this.lastPointAdded].timestampValue;
            }
        }

        private void getAverageValues()
        {
            this.averageFirst = Vector2.Zero;
            this.averageLast = Vector2.Zero;
            //Mittelwerte der ersten und letzten 10 Eintraege
            for (int i = 0; i < this.pointArray.Count() && i < AVERAGECOUNT; i++)
            {
                //abfangen
                if ((this.firstPoint + i) < this.pointArray.Count() &&
                    (this.lastPointAdded - i) < this.pointArray.Count() &&
                    (this.pointArray.ElementAt<Puzzle_RawPoint>(this.firstPoint + i) != null) &&
                    (this.pointArray.ElementAt<Puzzle_RawPoint>(this.lastPointAdded - i) != null))
                {
                    this.averageFirst.X += this.pointArray.ElementAt<Puzzle_RawPoint>(this.firstPoint + i).Xpos;
                    this.averageFirst.Y += this.pointArray.ElementAt<Puzzle_RawPoint>(this.firstPoint + i).Ypos;

                    this.averageLast.X += this.pointArray.ElementAt<Puzzle_RawPoint>(this.lastPointAdded - i).Xpos;
                    this.averageLast.Y += this.pointArray.ElementAt<Puzzle_RawPoint>(this.lastPointAdded - i).Ypos;
                }
            }
            //Durchschnitt berechnen
            this.averageFirst.X /= AVERAGECOUNT;
            this.averageFirst.Y /= AVERAGECOUNT;
            this.averageLast.X /= AVERAGECOUNT;
            this.averageLast.Y /= AVERAGECOUNT;
        }
    }
}
